package com.burgstaller.aGTD;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import android.app.DatePickerDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

import com.burgstaller.aGTD.utils.AbstractItemEditor;
import com.burgstaller.aGTD.utils.SmartCursorAdapter;
import com.burgstaller.provider.AGtd;

public class TaskEditor extends AbstractItemEditor implements OnFocusChangeListener {
	/**
	 * The columns we are interested in from the database
	 */
	private static final String[] PROJECTION = new String[] {
			AGtd.Tasks._ID, 
			AGtd.Tasks.TITLE, 			// 1 
            AGtd.Tasks.MODIFIED_DATE, 	// 2
            AGtd.Tasks.FK_CONTEXT_ID, 	// 3
            AGtd.Tasks.FK_PROJECT_ID, 	// 4
            AGtd.Tasks.COMPLETED,		// 5
            AGtd.Tasks.NOTES,			// 6
            AGtd.Tasks.START_DATE,		// 7
            AGtd.Tasks.DUE_DATE,		// 8
            AGtd.Tasks.SYNC_STATUS 		// 9
	};
	
	private static final int MODIFIED_INDEX = 2;
	private static final int FK_CONTEXT_ID_INDEX = 3;
	private static final int FK_PROJECT_ID_INDEX = 4;
	private static final int COMPLETD_INDEX = 5;
	private static final int NOTES_INDEX = 6;
	private static final int STARTDATE_INDEX = 7;
	private static final int DUEDATE_INDEX = 8;
	private static final int SYNC_STATUS_INDEX = 9;
	
	private static final String ORIGINAL_CONTENT = "origContent";

	private static final String[] CONTEXT_PROJECTION = new String[] { 
		AGtd.Contexts.TITLE,		// index 0
		AGtd.Contexts._ID			// index 1
	};
	private static final String[] PROJECT_PROJECTION = new String[] { 
		AGtd.Projects.TITLE,		// index 0
		AGtd.Projects._ID			// index 1
	};

	private TextView m_startDateDisplay;
	private CheckBox m_completedCheckBox;
	private Date m_startDate;
	private Date m_dueDate;

    private DatePicker.OnDateSetListener m_startDateSetListener =
        new DatePicker.OnDateSetListener() {

            public void dateSet(DatePicker view, int year, int monthOfYear,
                    int dayOfMonth) {
            	Calendar cal = Calendar.getInstance();
            	cal.set(Calendar.YEAR, year);
            	cal.set(Calendar.MONTH, monthOfYear);
            	cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
            	m_startDate = cal.getTime();
                updateDisplay();
            }
        };
        
    private DatePicker.OnDateSetListener m_dueDateSetListener = 
    	new DatePicker.OnDateSetListener() {
	        public void dateSet(DatePicker view, int year, int monthOfYear,
	                int dayOfMonth) {
            	Calendar cal = Calendar.getInstance();
            	cal.set(Calendar.YEAR, year);
            	cal.set(Calendar.MONTH, monthOfYear);
            	cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
            	m_dueDate = cal.getTime();
                updateDisplay();
	        }
    	};
	private String mOriginalContent;

	private Cursor m_contextCursor;

	private AutoCompleteTextView m_contextBox;

	private SimpleCursorAdapter m_contextAdapter;

	private SmartCursorAdapter m_projectAdapter;

	private Cursor m_projectCursor;

	private AutoCompleteTextView m_projectBox;

	private EditText m_notesBox;

	private Button m_pickStartDate;

	private Button m_pickDueDate;

	private TextView m_dueDateDisplay;
	
	private DateFormat m_dateFormat;
	
	private boolean m_backSelected = false;
        
	@Override
	protected int getContentLayoutId() {
		return R.layout.task_editor;
	}
	
	@Override
	protected void onCreate(Bundle icicle) {
		Log.i(AGtd.LOG_TAG, "TaskEditor. onCreate: url: " + getIntent().getData());
		super.onCreate(icicle);
		
		m_backSelected = false;
		m_dateFormat = SimpleDateFormat.getDateInstance();
		m_contextCursor = managedQuery(AGtd.Contexts.CONTENT_URI, 
				CONTEXT_PROJECTION, 
				null, null);
		m_projectCursor = managedQuery(AGtd.Projects.CONTENT_URI, 
				PROJECT_PROJECTION, 
				null, null);
		// Use an existing ListAdapter that will map an array
		// of strings to TextViews

		m_contextAdapter = new SmartCursorAdapter(this,
				android.R.layout.simple_list_item_1, m_contextCursor,
				CONTEXT_PROJECTION,
				new int[] { android.R.id.text1 }, AGtd.Contexts.CONTENT_URI,
				AGtd.Contexts.DEFAULT_SORT_ORDER);
		m_projectAdapter = new SmartCursorAdapter(this, 
				android.R.layout.simple_list_item_1, m_projectCursor, 
				PROJECT_PROJECTION, 
				new int[] {android.R.id.text1}, AGtd.Projects.CONTENT_URI,
				AGtd.Projects.DEFAULT_SORT_ORDER);

		m_contextBox = (AutoCompleteTextView) 
			findViewById(R.id.contextspinner);
		m_contextBox.setAdapter(m_contextAdapter);
		m_contextBox.setOnFocusChangeListener(this);
		
		m_projectBox = (AutoCompleteTextView)
			findViewById(R.id.projectspinner);
		m_projectBox.setAdapter(m_projectAdapter);
		m_projectBox.setOnFocusChangeListener(this);

		m_notesBox = (EditText) findViewById(R.id.notes);
		
		
		// initialize the date pickers
        m_startDateDisplay = (TextView) findViewById(R.id.startDateDisplay);
        m_dueDateDisplay = (TextView) findViewById(R.id.dueDateDisplay);

        m_pickStartDate = (Button) findViewById(R.id.pickStartDate);
        m_pickStartDate.setOnClickListener(this);
        
        m_pickDueDate = (Button) findViewById(R.id.pickDueDate);
        m_pickDueDate.setOnClickListener(this);
        m_completedCheckBox = (CheckBox) findViewById(R.id.task_completed);
        
        AGtdContentProvider.popCursor(m_contextCursor);
        AGtdContentProvider.popCursor(m_projectCursor);
	}

	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		super.finalize();
	}
	
    public void onClick(View v) {
    	if (v == m_pickStartDate) {
	    	if (m_startDate == null) {
	    		m_startDate = new Date();
	    	}
	    	Calendar calendar = Calendar.getInstance();
	    	calendar.setTime(m_startDate);
	    	
	        new DatePickerDialog(TaskEditor.this,
	                m_startDateSetListener,
	                calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 
	                calendar.get(Calendar.DAY_OF_MONTH), Calendar.SUNDAY).show();
    	} else if (v == m_pickDueDate) {
	    	if (m_dueDate == null) {
	    		m_dueDate = new Date();
	    	}
	    	Calendar calendar = Calendar.getInstance();
	    	calendar.setTime(m_dueDate);
	    	
	        new DatePickerDialog(TaskEditor.this,
	                m_dueDateSetListener,
	                calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 
	                calendar.get(Calendar.DAY_OF_MONTH), Calendar.SUNDAY).show();
    	}
    }

	Cursor findEntryById(long id, Uri url, String[] projection) {
		// find out which one is selected
		Cursor c = getContentResolver().query(Uri.withAppendedPath(url, "" + id), 
				projection, null, null, null);
		if (c.count() > 0) {
			c.first();
			return c;
		}
		AGtdContentProvider.popCursor(c);
		return null;
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		m_backSelected = false;
		long fkContextId = m_cursor.getLong(FK_CONTEXT_ID_INDEX);
		long fkProjectId = m_cursor.getLong(FK_PROJECT_ID_INDEX);

		Cursor c = findEntryById(fkContextId, AGtd.Contexts.CONTENT_URI, 
				CONTEXT_PROJECTION);
		if (c != null) {
			m_contextBox.setText(c.getString(0));
			AGtdContentProvider.popCursor(c);
			c = null;
		}
		
		c = findEntryById(fkProjectId, AGtd.Projects.CONTENT_URI,
				PROJECT_PROJECTION);
		if (c != null) {
			m_projectBox.setText(c.getString(0));
			AGtdContentProvider.popCursor(c);
			c = null;
		}
		m_completedCheckBox.setChecked(m_cursor.getInt(COMPLETD_INDEX) == 1);
		m_notesBox.setText(m_cursor.getString(NOTES_INDEX));
		long start = m_cursor.getLong(STARTDATE_INDEX);
		if (start > 0) {
			m_startDate = new Date(start);
		} else {
			m_startDate = null;
		}
		long due = m_cursor.getLong(DUEDATE_INDEX);
		if (due > 0) {
			m_dueDate = new Date(due);
		}
		updateDisplay();
	}
	
	@Override
	protected void onPause() {
		// this will take care about modified and the title
		super.onPause();
		
		Log.d(AGtd.LOG_TAG, "onPause saving, cursor: " + m_cursor);
		// now treat all the other fields
		if (m_cursor == null) {
			// no data left, so close
			return;
		}
		
		checkAndCreateXRefs();
		m_cursor.updateInt(COMPLETD_INDEX, m_completedCheckBox.isChecked() ? 
				1:0);
		m_cursor.updateString(NOTES_INDEX, m_notesBox.getText().toString());
		long startDate = (m_startDate != null) ? m_startDate.getTime() : -1;
		long dueDate = (m_dueDate != null) ? m_dueDate.getTime() : -1;
		m_cursor.updateLong(STARTDATE_INDEX, startDate);
		m_cursor.updateLong(DUEDATE_INDEX, dueDate);
		// update the status to modified in case the record is not new
		if (m_cursor.getInt(SYNC_STATUS_INDEX) != AGtd.Tasks.SYNC_STATUS_NEW) {
			m_cursor.updateInt(SYNC_STATUS_INDEX, 
				AGtd.Tasks.SYNC_STATUS_MODIFIED);
		}
		m_cursor.updateLong(MODIFIED_INDEX, System.currentTimeMillis());
		managedCommitUpdates(m_cursor);
	}
	
	@Override
	protected void onDestroy() {
		if (m_cursor != null) {
			AGtdContentProvider.popCursor(m_cursor);
			m_cursor = null;
		}
		super.onDestroy();
	}

	/**
	 * this method will check if the user has added new (unknown)
	 * values for project or context and prompt him for creating
	 * new records if necessary.
	 * @return true if the user is prompted (prevent exit)
	 */
	private boolean checkAndCreateXRefs() {
		// ok we have the data to store
		boolean result = false;
		
		// search the correct id of the entered context
		String context = m_contextBox.getText().toString();
		long id = lookupIdForTitle(context, AGtd.Contexts.CONTENT_URI,
				CONTEXT_PROJECTION, 0, 1);
		Log.d(AGtd.LOG_TAG, "context id for " + context + ", " + id);
		if (id >= 0) {
			Log.d(AGtd.LOG_TAG, "updating context id to: " + id);
			m_cursor.updateLong(FK_CONTEXT_ID_INDEX, id);
		} else {
			Log.w(AGtd.LOG_TAG, "unknown context:" + context);
			result |= createContextIfNecessary();
		}

		String project = m_projectBox.getText().toString();
		id = lookupIdForTitle(project, AGtd.Projects.CONTENT_URI,
				PROJECT_PROJECTION, 0, 1);
		Log.d(AGtd.LOG_TAG, "project id for " + project + ", " + id);
		if (id >= 0) {
			Log.d(AGtd.LOG_TAG, "updating project id to: " + id);
			m_cursor.updateLong(FK_PROJECT_ID_INDEX, id);
		} else {
			Log.w(AGtd.LOG_TAG, "unknown project id:" + id);
			result |= createProjectIfNecessary();
		}
		return result;
	}

	private long lookupIdForTitle(String title, Uri contentUri, 
			String[] projection, int columnIndexToSearch, 
			int columnIndexForId) {
		Cursor c = getContentResolver().query(contentUri, projection, 
				projection[columnIndexToSearch] + "= ?", new String[] {title}, 
				null);
		long result = -1;
		if (c.count() == 1) {
			c.first();
			result = c.getLong(columnIndexForId);
		}
		AGtdContentProvider.popCursor(c);
		return result;
	}

	private void updateDisplay() {
		m_startDateDisplay.setBackgroundColor(Color.TRANSPARENT);
		m_startDateDisplay.setTextColor(Color.GRAY);	    		
		if (m_startDate != null) {
	    	m_startDateDisplay.setText(m_dateFormat.format(m_startDate));
	    	long start = m_startDate.getTime();
	    	if (start > 0 && System.currentTimeMillis() < start) {
	    		m_startDateDisplay.setBackgroundColor(Color.GREEN);
	    		m_startDateDisplay.setTextColor(Color.BLACK);
	    	} else if (start > 0) {
	    		m_startDateDisplay.setBackgroundColor(Color.RED);
	    		m_startDateDisplay.setTextColor(Color.GRAY);
	    	}
		}
		m_dueDateDisplay.setBackgroundColor(Color.TRANSPARENT);
		m_dueDateDisplay.setTextColor(Color.GRAY);
		if (m_dueDate != null) {
			m_dueDateDisplay.setText(m_dateFormat.format(m_dueDate));
			long due = m_dueDate.getTime();
	    	if (due > 0 && due > System.currentTimeMillis()) {
	    		m_dueDateDisplay.setBackgroundColor(Color.GREEN);
	    		m_dueDateDisplay.setTextColor(Color.BLACK);
	    	} else if (due > 0) {
	    		m_dueDateDisplay.setBackgroundColor(Color.RED);
	    		m_dueDateDisplay.setTextColor(Color.GRAY);
	    	}
		}
		
	}

	@Override
	protected String[] getProjectionMap() {
		return PROJECTION;
	}

	/** 
	 * is called when the user moves from one field to the next.
	 * @param view the view/widget that had the focus changed
	 * @param focused if true then the wiget got the focus, otherwise it lost 
	 * 	it. 
	 */
	public void onFocusChanged(View view, boolean focused) {
		if (focused) {
			return;
		}
		
		// only interested in when the focus goes away
		if (view == m_contextBox) {
			createContextIfNecessary();
			
		} else if (view == m_projectBox) {
			createProjectIfNecessary();
			
		}
	}

	private boolean createProjectIfNecessary() {
		String project = m_projectBox.getText().toString();
		boolean result = false;
		if (project.length() == 0) {
			return false;
		}
		long id = lookupIdForTitle(project, AGtd.Projects.CONTENT_URI,
				PROJECT_PROJECTION, 0, 1);
		Log.d(AGtd.LOG_TAG, "project id for " + project + ", " + id);
		if (id < 0) {
			result = true;
			String message = String.format(getString(
					R.string.alert_create_new_project), project);

			this.showAlert(getString(R.string.alert_new_project_header), 
					0, 
					message, 
					getString(R.string.alert_button_create), 
					new OnClickListener() {
						public void onClick(DialogInterface dialog, 
								int whichButton) {
							createProject();
							finishIfNecessary();
						}
					}, true, 
					new OnCancelListener() {
						public void onCancel(DialogInterface dialog) {
							m_projectBox.setText("");
							finishIfNecessary();
						}
					});
		}
		return result;
	}

	private boolean createContextIfNecessary() {
		String context = m_contextBox.getText().toString();
		boolean result = false;
		if (context.length() == 0) {
			return false;
		}
		
		long id = lookupIdForTitle(context, AGtd.Contexts.CONTENT_URI,
				CONTEXT_PROJECTION, 0, 1);
		
		Log.d(AGtd.LOG_TAG, "context id for " + context + ", " + id);
		if (id < 0) {
			result = true;
			String message = String.format(getString(
					R.string.alert_create_new_context), context);

			this.showAlert(getString(R.string.alert_new_context_header), 
					0, message, getString(R.string.alert_button_create), 
					new OnClickListener() {
						public void onClick(DialogInterface dialog, 
								int whichButton) {
							createContext();
							finishIfNecessary();
						}
					}, true, 
					new OnCancelListener() {
						public void onCancel(DialogInterface dialog) {
							m_contextBox.setText("");
							finishIfNecessary();
						}
					});
			
		}
		return result;
	}
	
	void createContext() {
		ContentValues values = new ContentValues();
		values.put(AGtd.Contexts.TITLE, m_contextBox.getText().toString());
		getContentResolver().insert(AGtd.Contexts.CONTENT_URI, values);
	}
	
	void createProject() {
		ContentValues values = new ContentValues();
		values.put(AGtd.Contexts.TITLE, m_projectBox.getText().toString());
		getContentResolver().insert(AGtd.Projects.CONTENT_URI, values);		
	}
	
	@Override
	public void finish() {
		Log.i(AGtd.LOG_TAG, "Finish called");
		if (!checkAndCreateXRefs()) {
			Log.i(AGtd.LOG_TAG, "no new category");
			// reset the back flag
			m_backSelected = false;
			
			// only let the user exit if he answers the prompts 
			super.finish();
			return;
		}
		// remember that the user wanted to go back
		m_backSelected = true;
	}

	private void finishIfNecessary() {
		if (m_backSelected) {
			m_backSelected = false;
			finish();
		}
	}
}
